#include "ws2812.h"

// 一个颜色 3 种元色，一个元色 8 个码元(ws2812 比特)，一个码元 4 个 spi 比特，一个字节 8 个比特，
// rst 信号不需要存储与发送，只需要将最后一位置为 0，spi 总线 mosi 会保持在 0，确保超过 rst 所需时间之前不要立即刷新下一帧就行,
// 如果想要使用 DMA 发送完成中断，那么需要发送 rst 信号
uint8_t ws2812Buffer[WS2812_LAMP_NUM * 3 * 8 * 4 / 8 + WS2812_RST_BYTES];

/**
 * @brief 设置特定索引号单颗灯珠颜色
 * 
 * @param ws : ws2812 设备结构体
 * @param pixel : 灯珠信息
 * @param index : 索引号，1 开始
 */
void ws2812_set_1_color_index(struct ws2812Stu *ws, struct ws2812PixelDescribeStu *pixel, uint16_t index){
    uint8_t i;
    ws2812ColorStu light = {
        .green = 0,
        .red = 0,
        .blue = 0,
    };

    if(index < 1 || index > ws->lampNum){
        return ;
    }

    for(i = 0; i < 8; i ++){
        if((pixel->green >> i) & 0x1){
            light.green |= WS2812_1_CODE << (28 - i*4);
        }else {
            light.green |= WS2812_0_CODE << (28 - i*4);
        }
    }
    
    for(i = 0; i < 8; i ++){
        if((pixel->red >> i) & 0x1){
            light.red |= WS2812_1_CODE << (28 - i*4);
        }else {
            light.red |= WS2812_0_CODE << (28 - i*4);
        }
    }
    
    for(i = 0; i < 8; i ++){
        if((pixel->blue >> i) & 0x1){
            light.blue |= WS2812_1_CODE << (28 - i*4);
        }else {
            light.blue |= WS2812_0_CODE << (28 - i*4);
        }
    }

    *(((ws2812ColorStu *)(ws->buffer)) + index - 1) = light;
}

/**
 * @brief 设置特定坐标单颗灯珠颜色
 * 
 * @param ws : ws2812 结构体
 * @param pixel : 灯珠信息
 */
void ws2812_set_1_color_xy(struct ws2812Stu *ws, struct ws2812PixelDescribeStu *pixel){
    uint8_t i;
    ws2812ColorStu light = {
        .green = 0,
        .red = 0,
        .blue = 0,
    };

    if(ws->lampIndexRemap(pixel->x, pixel->y) < 1 || ws->lampIndexRemap(pixel->x, pixel->y) > ws->lampNum){
        return ;
    }

    for(i = 0; i < 8; i ++){
        if((pixel->green >> i) & 0x1){
            light.green |= WS2812_1_CODE << (28 - i*4);
        }else {
            light.green |= WS2812_0_CODE << (28 - i*4);
        }
    }
    
    for(i = 0; i < 8; i ++){
        if((pixel->red >> i) & 0x1){
            light.red |= WS2812_1_CODE << (28 - i*4);
        }else {
            light.red |= WS2812_0_CODE << (28 - i*4);
        }
    }
    
    for(i = 0; i < 8; i ++){
        if((pixel->blue >> i) & 0x1){
            light.blue |= WS2812_1_CODE << (28 - i*4);
        }else {
            light.blue |= WS2812_0_CODE << (28 - i*4);
        }
    }

    *(((ws2812ColorStu *)(ws->buffer)) + ws->lampIndexRemap(pixel->x, pixel->y) - 1) = light;
}

/* 废弃
void ws2812_set_color(struct ws2812Stu *ws, uint32_t lampIndex, uint8_t red, uint8_t green, uint8_t blue){
    uint32_t i;
    struct ws2812ColorStu color;

    for(i = 0; i < 4; i ++){
        switch((green >> (i*2)) && 0x03){
            case 0:
                *(((uint8_t *)&(color.G1)) - i) = WS2812_00_CODE;
                break;

            case 1:
                *(((uint8_t *)&(color.G1)) - i) = WS2812_01_CODE;
                break;

            case 2:
                *(((uint8_t *)&(color.G1)) - i) = WS2812_10_CODE;
                break;

            case 3:
                *(((uint8_t *)&(color.G1)) - i) = WS2812_11_CODE;
                break;
        }
    }

    for(i = 0; i < 4; i ++){
        switch((red >> (i*2)) && 0x03){
            case 0:
                *(((uint8_t *)&(color.R1)) - i) = WS2812_00_CODE;
                break;

            case 1:
                *(((uint8_t *)&(color.R1)) - i) = WS2812_01_CODE;
                break;

            case 2:
                *(((uint8_t *)&(color.R1)) - i) = WS2812_10_CODE;
                break;

            case 3:
                *(((uint8_t *)&(color.R1)) - i) = WS2812_11_CODE;
                break;
        }
    }

    for(i = 0; i < 4; i ++){
        switch((blue >> (i*2)) && 0x03){
            case 0:
                *(((uint8_t *)&(color.B1)) - i) = WS2812_00_CODE;
                break;

            case 1:
                *(((uint8_t *)&(color.B1)) - i) = WS2812_01_CODE;
                break;

            case 2:
                *(((uint8_t *)&(color.B1)) - i) = WS2812_10_CODE;
                break;

            case 3:
                *(((uint8_t *)&(color.B1)) - i) = WS2812_11_CODE;
                break;
        }
    }
    
    *((struct ws2812ColorStu *)&(ws->buffer[(lampIndex - 1) * 8 * 3 * 4 / 8])) = color;
}
*/

/**
 * @brief 将所有灯珠设置为一种颜色
 * 
 * @param ws 
 * @param red 
 * @param green 
 * @param blue 
 */
void ws2812_set_all_color(struct ws2812Stu *ws, uint8_t red, uint8_t green, uint8_t blue){
    
    uint32_t i;
    ws2812ColorStu light = {
        .green = 0,
        .red = 0,
        .blue = 0,
    };

        for(i = 0; i < 8; i ++){
            if((green >> i) & 0x1){
                light.green |= WS2812_1_CODE << (28 - i*4);
            }else {
                light.green |= WS2812_0_CODE << (28 - i*4);
            }
        }
        
        for(i = 0; i < 8; i ++){
            if((red >> i) & 0x1){
                light.red |= WS2812_1_CODE << (28 - i*4);
            }else {
                light.red |= WS2812_0_CODE << (28 - i*4);
            }
        }
        
        for(i = 0; i < 8; i ++){
            if((blue >> i) & 0x1){
                light.blue |= WS2812_1_CODE << (28 - i*4);
            }else {
                light.blue |= WS2812_0_CODE << (28 - i*4);
            }
        }

    for(i = 0; i < ws->lampNum; i ++){
        *(((ws2812ColorStu *)(ws->buffer)) + i) = light;
    }
}

void ws2812_init(struct ws2812Stu *ws){
    uint32_t i;
    ws2812ColorStu lightDown = {
        .green = WS2812_0000_0000_CODE,
        .red = WS2812_0000_0000_CODE,
        .blue = WS2812_0000_0000_CODE,
    };

    for(i = 0; i < ws->lampNum; i ++){
        *(((ws2812ColorStu *)(ws->buffer)) + i) = lightDown;
    }

    ws2812_refresh(ws);
}

/**
 * @brief 刷新一帧画面
 * 
 * @param ws 
 */
void ws2812_refresh(struct ws2812Stu *ws){
    HAL_SPI_Transmit_DMA(ws->hspi, ws->buffer, ws->lampNum * 3 * 8 * 4 / 8 + WS2812_RST_BYTES);
}

const uint8_t digit[10][5] = {
    [0] = {
        0x7,
        0x5,
        0x5,
        0x5,
        0x7,
    },
    [1] = {
        0x2,
        0x2,
        0x2,
        0x2,
        0x2,            
    },
    [2] = {
        0x7,
        0x1,
        0x7,
        0x4,
        0x7,
    },
    [3] = {
        0x7,
        0x1,
        0x7,
        0x1,
        0x7,
    },
    [4] = {
        0x5,
        0x5,
        0x7,
        0x1,
        0x1,
    },
    [5] = {
        0x7,
        0x4,
        0x7,
        0x1,
        0x7,
    },
    [6] = {
        0x7,
        0x4,
        0x7,
        0x5,
        0x7,
    },
    [7] = {
        0x7,
        0x1,
        0x1,
        0x1,
        0x1,
    },
    [8] = {
        0x7,
        0x5,
        0x7,
        0x5,
        0x7,
    },
    [9] = {
        0x7,
        0x5,
        0x7,
        0x1,
        0x7,
    },
};

void ws_show_digit(struct ws2812Stu *ws, uint8_t number, struct ws2812PixelDescribeStu *pixel){
    
    uint8_t i;
    number = number%10;
    struct ws2812PixelDescribeStu pix = {
        .x = 0,
        .y = 0,
        .red = 0,
        .green = 0,
        .blue = 0,
    };
    
    for(i = 0; i < 5; i ++){
        if((digit[number][i] >> 2) & 0x1){
            pix.x = pixel->x;
            pix.y = pixel->y + i;
            pix.red = pixel->red;
            pix.green = pixel->green;
            pix.blue = pixel->blue;
            ws2812_set_1_color_xy(ws, &pix);
        }else {
            pix.x = pixel->x;
            pix.y = pixel->y + i;
            pix.red = 0;
            pix.green = 0;
            pix.blue = 0;
            ws2812_set_1_color_xy(ws, &pix);
        }
        if((digit[number][i] >> 1) & 0x1){
            pix.x = pixel->x + 1;
            pix.y = pixel->y + i;
            pix.red = pixel->red;
            pix.green = pixel->green;
            pix.blue = pixel->blue;
            ws2812_set_1_color_xy(ws, &pix);
        }else {
            pix.x = pixel->x + 1;
            pix.y = pixel->y + i;
            pix.red = 0;
            pix.green = 0;
            pix.blue = 0;
            ws2812_set_1_color_xy(ws, &pix);
        }
        if((digit[number][i]) & 0x1){
            pix.x = pixel->x + 2;
            pix.y = pixel->y + i;
            pix.red = pixel->red;
            pix.green = pixel->green;
            pix.blue = pixel->blue;
            ws2812_set_1_color_xy(ws, &pix);
        }else {
            pix.x = pixel->x + 2;
            pix.y = pixel->y + i;
            pix.red = 0;
            pix.green = 0;
            pix.blue = 0;
            ws2812_set_1_color_xy(ws, &pix);
        }
    }
}

uint16_t myWs_index_remap(uint16_t x, uint16_t y){
    // 异形屏映射

    return 0;
}
